package com.voole.security.filter;

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

/**
 * SecurityFilter过滤类
 * 
 * 登陆后，每次访问资源都通过这个拦截器拦截。
 * 它是CustomSecurityMetadataSource和CustomAccessDecisionManager前置，
 * 它通过后，会先调用CustomSecurityMetadataSource.getAttributes()
 */
public class CustomSecurityFilter extends AbstractSecurityInterceptor implements Filter {

	//配置文件注入
	@Resource
	private FilterInvocationSecurityMetadataSource securityMetadataSource;//必须有set、get方法
	
	//登陆后，每次访问资源都通过这个拦截器拦截
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
		FilterInvocation fi = new FilterInvocation(request, response, chain); 
		invoke(fi);  
	}
	
	public Class<? extends Object> getSecureObjectClass() { 
		return FilterInvocation.class;    
	}  
	
	public void invoke(FilterInvocation fi) throws IOException, ServletException {
	//fi里面有一个被拦截的url
	//最重要的是beforeInvocation这个方法，
	//它首先会调用CustomSecurityMetadataSource类的getAttributes方法获取被拦截url所需的权限，
	//再调用CustomAccessDecisionManager类decide方法判断用户是否够权限
	InterceptorStatusToken token = super.beforeInvocation(fi);
	try {
		//执行下一个拦截器
		fi.getChain().doFilter(fi.getRequest(), fi.getResponse());   
		} finally { 
			super.afterInvocation(token, null);  
		}   
	}

	public SecurityMetadataSource obtainSecurityMetadataSource() { 
		return this.getSecurityMetadataSource();   
	} 
	
	public void destroy() {  
	}
	
	public void init(FilterConfig arg0) throws ServletException {  
	}

	public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
		return securityMetadataSource;
	}

	public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
		this.securityMetadataSource = securityMetadataSource;
	}
	

}